home *** CD-ROM | disk | FTP | other *** search
- char *ckzv = "Data General file support, 5A(065) 12 May 93";
-
- /* C K D F I O -- Kermit file system support for AOS/VS & derivatives */
-
- /*
- Author: Frank da Cruz (fdc@columbia.edu, FDCCU@CUVMA.BITNET),
- Columbia University Academic Information Systems, New York City.
-
- Copyright (C) 1985, 1993, Trustees of Columbia University in the City of New
- York. The C-Kermit software may not be, in whole or in part, licensed or
- sold for profit as a software product itself, nor may it be included in or
- distributed with commercial products or otherwise distributed by commercial
- concerns to their clients or customers without written permission of the
- Office of Kermit Development and Distribution, Columbia University. This
- copyright notice must not be removed, altered, or obscured.
-
- Adapted to Data General computers in 1985 by:
- Phil Julian, SAS Institute, Inc., Box 8000, Cary, NC 27512-8000,
- with additional help:
- For using sys_gnfn() in fgen(), instead of my kludge:
- Victor Johansen, Micro_rel, 2343 W 10th Place, Tempe AZ 85281
- For using dg_open() for the pipe in zxcmd(), and also for using
- sys_proc() in start_cli():
- Richard Lamb, MIT, 77 Mass. Ave., Room 35-437, Cambridge MA 02139
- Adapted to C-Kermit 5A by Eugenia Harris (ENH) at Data General, who
- thanks Larry McCoskery, also at Data General, for many library routines
- and much debugging assistance.
- */
-
- /*
- Support for DG/UX and other non-AOS/VS implementations
- has been removed -- only exception is MV/UX which has been left in but
- has not been tested and probably doesn't work. DG/UX Kermit can be
- built with the cku* modules from Columbia University. --ENH
- */
-
- /* Includes */
-
- #nolist
- #include "ckcdeb.h" /* Typedefs, debug formats, etc */
- #include "ckcker.h" /* Kermit definitions */
- #include <ctype.h> /* Character types */
- #include <stdio.h> /* Standard i/o */
- #include <time.h>
- #include <packets:create.h>
- #include <packets:common.h>
- #include <memory.h>
- #include <dglib.h>
- #include <sys_calls.h>
- #include <packets:process.h>
- #include <packets/filestatus.h> /* Used for ?GNFN */
- #include <paru.h>
- #include <bit.h>
- #include <sys/dir.h> /* Directory structure */
- #include <sys/stat.h> /* File status */
- #list
-
- /* The DG compiler version 3.21 has a bug in the get*id() functions, which
- * cause the program to go into an infinite loop. These functions should
- * return -1 unless the system is in a UNIX environment, so I made the
- * appropriate kludges. -- Phil Julian, 8 April 87
- */
- #define getgid() -1
- #define getuid() -1
- #define geteuid() -1
- #define MAXNAMLEN ($MXFN-1)
- #define MAXPATH ($MXPL-1) /* both from system PARU.32 */
- #define DIRSEP ':'
- #define ISDIRSEP(c) (((c)==':') || ((c)=='^') || ((c)=='='))
- #define TIMESTAMP
- #define MAXWLD 500
- #define fork() vfork()
-
- char *ckzsys = " Data General AOS/VS";
-
- /* Definitions of system commands for AOS/VS */
-
- char *DIRCMD = "filestatus/sort/assortment "; /* For directory listing */
- char *DIRCM2 = "filestatus/sort/assortment"; /* For full directory list */
- char *DELCMD = "delete/v "; /* For file deletion */
- char *TYPCMD = "type "; /* For typing a file */
-
- char *PWDCMD = "directory"; /* For saying where I am */
-
- /* SPACMD now returns space in current directory rather than home dir. */
- char *SPACMD = "space ="; /* For space in current directory */
- char *SPACM2 = "space "; /* For space in specified directory */
-
- char *WHOCMD = "who [!sons op:exec]";
-
- /*
- Functions (n is one of the predefined file numbers from ckermi.h):
-
- zopeni(n,name) -- Opens an existing file for input.
- zopeno(n,name) -- Opens a new file for output.
- zclose(n) -- Closes a file.
- zchin(n,&c) -- Gets the next character from an input file.
- zsout(n,s) -- Write a null-terminated string to output file, buffered.
- zsoutl(n,s) -- Like zsout, but appends a line terminator.
- zsoutx(n,s,x) -- Write x characters to output file, unbuffered.
- zchout(n,c) -- Add a character to an output file, unbuffered.
- zchki(name) -- Check if named file exists and is readable, return size.
- zchko(name) -- Check if named file can be created.
- zchkspa(name,n) -- Check if n bytes available for file
- znewn(name,s) -- Make a new unique file name based on the given name.
- zdelet(name) -- Delete the named file.
- zxpand(string) -- Expands the given wildcard string into a list of files.
- znext(string) -- Returns the next file from the list in "string".
- zxcmd(cmd) -- Execute the command in a lower fork.
- zclosf() -- Close input file associated with zxcmd()'s lower fork.
- zrtol(n1,n2) -- Convert remote filename into local form.
- zltor(n1,n2) -- Convert local filename into remote form.
- zchdir(dirnam) -- Change working directory.
- zhome() -- Return pointer to home directory name string.
- zkself() -- Kill self, log out own job.
- zsattr(struct zattr *) -- Return attributes for file which is being sent.
- zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
- zrename(old, new) -- Rename a file.
- */
-
- /* Some systems define these in include files, others don't... */
- #ifndef R_OK
- #define R_OK 4 /* For access */
- #endif /* ifndef R_OK */
-
- #ifndef W_OK
- #define W_OK 2
- #endif /* ifndef W_OK */
-
- #ifdef UXIII
- #include <fcntl.h>
- #define MAXNAMLEN DIRSIZ
- #endif
-
- #ifndef O_RDONLY
- #define O_RDONLY 000
- #endif /* ifndef O_RDONLY */
-
- /* Declarations */
-
- int wildcarlb; /* Wild card ^ or # */
- int maxnam = MAXNAMLEN; /* Available to the outside */
- int maxpath = MAXPATH;
-
-
- FILE *fp[ZNFILS] = { /* File pointers */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL };
-
- /* Buffers and pointers used in buffered file input */
-
- #ifdef DYNAMIC
- extern char *zinbuffer, *zoutbuffer;
- #else
- extern char zinbuffer[], zoutbuffer[];
- #endif /* ifdef DYNAMIC */
-
- extern char *zinptr, *zoutptr;
- extern int zincnt, zoutcnt;
- extern int wildxpand;
-
- static long iflen = -1L; /* Input file length */
- static PID_T pid; /* pid of child fork */
- #ifdef SASMOD /* For remote Kermit command */
- static int savout, saverr; /* saved stdout and stderr streams */
- #endif /* ifdef SASMOD */
- static int fcount; /* Number of files in wild group */
- static char nambuf[MAXNAMLEN+1]; /* Buffer for a filename */
- char *malloc(), *getenv(), *strcpy(); /* System functions */
- extern errno; /* System error code */
-
- char *mtchs[MAXWLD]; /* Matches found for filename */
- static char **mtchptr; /* Pointer to current match */
- static char zmbuf[200];
-
- /* Z K S E L F -- Kill Self: log out own job, if possible. */
-
- zkself() { /* For "bye", but no guarantee! */
-
- /* sys_term works better than kill() on the DG, but does not log off. */
-
- char *msg ="bye ";
- int ac2;
- ac2 = (int) msg;
- return(sys_term(getpid(),0,ac2));
- }
-
- /* Z O P E N I -- Open an existing file for input. */
-
- zopeni(n,name) int n; char *name; {
- debug(F111," zopeni",name,n);
- debug(F101," fp","",(int) fp[n]);
- if (chkfn(n) != 0) return(0);
- if (n == ZSYSFN) { /* Input from a system function? */
- debug(F110," invoking zxcmd",name,0);
- return(zxcmd(name)); /* Try to fork the command */
- }
- if (n == ZSTDIO) { /* Standard input? */
- if (isatty(0)) {
- ermsg("Terminal input not allowed");
- debug(F110,"zopeni: attempts input from unredirected stdin","",0);
- return(0);
- }
- fp[ZIFILE] = stdin;
- return(1);
- }
- fp[n] = fopen(name,"r"); /* Real file. */
- debug(F111," zopeni", name, (int) fp[n]);
- if (fp[n] == NULL) perror("zopeni");
- return((fp[n] != NULL) ? 1 : 0);
- }
-
- /* Z O P E N O -- Open a new file for output. */
-
- zopeno(n,name,zz,fcb)
- int n; char *name; struct zattr *zz; struct filinfo *fcb; {
-
- char p[3];
- char myname[] = "zopeno()";
- long validate();
-
- debug(F111," zopeno",name,n);
-
- if (fcb) {
- debug(F101,"zopeno fcb disp","",fcb->dsp);
- debug(F101,"zopeno fcb type","",fcb->typ);
- debug(F101,"zopeno fcb char","",fcb->cs);
- } else {
- debug(F100,"zopeno fcb is NULL","",0);
- }
- if (n != ZDFILE)
- debug(F111," zopeno",name,n);
-
- if (chkfn(n) != 0) return(0);
- if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */
- fp[ZOFILE] = stdout;
- if (n != ZDFILE)
- debug(F101," fp[]=stdout", "",fp[n]);
- zoutcnt = 0;
- zoutptr = zoutbuffer;
- return(1);
- }
-
- /* ENH - in VS, the creation time can only be set on the */
- /* create, so if the file exists and a creation date is specified */
- /* we will delete the existing file and create the new with requested */
- /* creation date. If no date is given, or it's invalid, we will */
- /* not bother creating the file, as it will be created implicitly */
- /* on the open. Note that we ignore errors from the routine to */
- /* set the creation date (and create the file), the assumption */
- /* being that if it fails, the file is not created, but there's */
- /* still a possibility that it might be created on the open. If */
- /* not, the error will be caught there. Note that this whole pro- */
- /* cedure is only invoked when the file collsion action is "update". */
- /* That is the only time we will get to this point and find that a */
- /* file of the same name already exists. */
-
- strcpy(p,"w");
- if (fcb) { /* If called with an FCB... */
- if (fcb->dsp == XYFZ_A) { /* Does it say Append? */
- debug(F101,"zopeno opening for append access",name,0);
- strcpy(p,"a"); /* If so, open for append access */
- } else if (file_exists(name) != 0) { /* If it exists, delete it */
- if (zdelet(name) != 0) /* and create w/incoming date */
- debug(F101,"zopeno error deleting existing file",name,0);
- else debug(F101,"zopeno existing file deleted",name,0);
- if (zz->date.len > 0) { /* if creation date specified */
- debug(F101,"zopeno creating file with incoming date",
- name,0);
- set_creation_date(name,zz->date.val); /* set it */
- strcpy(p,"r+");
- }
- }
- }
-
- fp[n] = fopen(name,p); /* A real file, try to open */
- if (fp[n] == NULL) {
- perror("zopeno can't open");
- } else {
- if (n == ZDFILE) setbuf(fp[n],NULL); /* Debugging file unbuffered */
- }
-
- zoutcnt = 0; /* (PWP) reset output buffer */
- zoutptr = zoutbuffer;
- if (n != ZDFILE)
- debug(F101, " fp[n]", "", (int) fp[n]);
- return((fp[n] != NULL) ? 1 : 0);
- }
-
- /* Z C L O S E -- Close the given file. */
-
- /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */
-
- int
- zclose(n) int n; {
- int x, x2;
-
- if (chkfn(n) < 1) return(0); /* Check range of n */
-
- if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
- x2 = zoutdump();
- else
- x2 = 0;
-
- x = 0;
-
- if (fp[ZSYSFN]) { /* If system function */
- x = zclosf(n); /* do it specially */
- } else {
- if ((fp[n] != stdout) && (fp[n] != stdin)) x = fclose(fp[n]);
- fp[n] = NULL;
- }
- iflen = -1L; /* invalidate file length */
- if (x == EOF)
- return (-1);
- else if (x2 < 0)
- return (-1);
- else
- return (1);
- }
-
- /* Z C H I N -- Get a character from the input file. */
-
- /* Returns -1 if EOF, 0 otherwise with character returned in argument */
- int
- zchin(n,c) int n; int *c; {
- int a, x;
-
- /* (PWP) Just in case this gets called when it shouldn't. */
- if (n == ZIFILE) {
- x = zminchar();
- *c = x;
- return(x);
- }
-
- /* if (chkfn(n) < 1) return(-1); */
- a = getc(fp[n]);
- if (a == EOF) return(-1);
- *c = (CHAR) a & 0377;
- return(0);
- }
-
- /* Z S I N L -- Reads a line from file number n */
- /*
- Reads line from file number n and writes it to address provided by caller.
- Writing terminates when a newline is read, but the newline is discarded.
- Writing also terminates on EOF or if length x is exhausted. Returns 0
- on success and -1 on EOF
- */
- int
- zsinl(n,s,x) int n, x; char *s; {
- int a, z = 0; /* lifted verbatim from ckufio.c */
-
- if (chkfn(n) < 1) { /* Make sure file is open */
- return(-1);
- }
- a = -1;
- while (x--) {
-
- #ifndef NLCHAR
- int old;
- old = a; /* Previous character */
- #endif
-
- if (zchin(n,&a) < 0) { /* Read a character from the file */
- z = -1;
- break;
- }
-
- #ifdef NLCHAR
- if (a == (char) NLCHAR) break; /* Single-character line terminator */
- #else
- if (a == '\r') continue; /* CRLF line terminator */
- if (old == '\r') {
- if (a == '\n') break;
- else *s++ = '\r';
- }
- #endif /* NLCHAR */
-
- *s = a;
- s++;
- }
- *s = '\0';
- return(z);
- }
-
-
-
- /* Z I N F I L L -- Reads characters from ZIFILE when sending files. */
- /*
- * Suggestion: if fread() returns 0, call ferror to find out what the
- * problem was. If it was not EOF, then return -2 instead of -1.
- * Upper layers (getpkt function in ckcfns.c) should set cxseen flag
- * if it gets -2 return from zminchar macro.
- */
- int
- zinfill() {
- int x;
-
- errno = 0;
- zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
-
- #ifdef COMMENT
- debug(F101,"zinfill fp","",fp[ZIFILE]);
- debug(F101,"zinfill zincnt","",zincnt);
- #endif
-
- if (zincnt == 0) {
-
- #ifdef ferror
- x = ferror(fp[ZIFILE]);
- debug(F101,"zinfill errno","",errno);
- debug(F101,"zinfill ferror","",x);
- if (x) return(-2);
- #endif /* ferror */
-
- x = feof(fp[ZIFILE]);
- debug(F101,"zinfill errno","",errno);
- debug(F101,"zinfill feof","",x);
- if (!x && ferror(fp[ZIFILE])) return(-2);
- return(-1);
- }
- zinptr = zinbuffer; /* set ptr to beginning, (== &zinbuffer[0]) */
- zincnt--; /* one less char in buffer */
- return((int)(*zinptr++) & 0377); /* because we return the first */
- }
-
- /* Z S O U T -- Write a string to the given file, buffered. */
-
- int
- zsout(n,s) int n; char *s; {
- if (chkfn(n) < 1) return(-1); /* Keep this here, prevents memory faults */
-
- #ifdef COMMENT
- while (*s) { /* (unbuffered for debugging) */
- write(fileno(fp[n]),s,1); ++s;
- }
- return(fputs(s,fp[n]) == EOF ? -1 : 0);
- #else
- if (n == ZSFILE)
- return(write(fileno(fp[n]),s,(int)strlen(s)));
- else
- return((fputs(s,fp[n]) == EOF) ? -1 : 0);
- #endif
- }
-
-
- /* Z S O U T L -- Write string to file, with line terminator, buffered */
-
- int
- zsoutl(n,s) int n; char *s; {
- /* if (chkfn(n) < 1) return(-1); */
- if (fputs(s,fp[n]) == EOF) return(-1);
- fputs("\n",fp[n]);
- return(0);
- }
-
- /* Z S O U T X -- Write x characters to file, unbuffered. */
-
- int
- zsoutx(n,s,x) int n, x; char *s; {
-
- #ifdef COMMENT
- if (chkfn(n) < 1) return(-1);
- return(write(fp[n]->_file,s,x));
- #endif
-
- return(write(fileno(fp[n]),s,x));
- }
-
-
- /* Z C H O U T -- Add a character to the given file. */
-
- /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */
-
- #ifdef CK_ANSIC
- zchout (register int n, char c)
- #else
- zchout(n,c) register int n; char c;
- #endif /* CK_ANSIC */
-
- /* zchout() */ {
-
- /* if (chkfn(n) < 1) return(-1); */
- if (n == ZSFILE)
- return(write(fileno(fp[n]),&c,1)); /* Use unbuffered for session log */
- else { /* Buffered for everything else */
- if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
- return(ferror(fp[n])?-1:0); /* Check to make sure */
- else /* Otherwise... */
- return(0); /* There was no error. */
- }
- }
-
- zoutdump() {
- int x;
- zoutptr = zoutbuffer; /* Reset buffer pointer in all cases */
- debug(F101,"zoutdump chars","",zoutcnt);
- if (zoutcnt == 0) { /* Nothing to output */
- return(0);
- } else if (zoutcnt < 0) { /* Unexpected negative argument */
- zoutcnt = 0; /* Reset output buffer count */
- return(-1); /* and fail. */
- }
-
- /* Frank Prindle suggested that replacing this fwrite() by an fflush() */
- /* followed by a write() would improve the efficiency, especially when */
- /* writing to stdout. Subsequent tests showed a 5-fold improvement! */
- /* if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) { */
-
- fflush(fp[ZOFILE]);
- if ((x = write(fileno(fp[ZOFILE]),zoutbuffer,zoutcnt)) == zoutcnt) {
- debug(F101,"zoutdump write ok","",zoutcnt);
- zoutcnt = 0; /* Reset output buffer count */
- return(0); /* write() worked OK */
- } else {
-
- debug(F101,"zoutdump write error","",errno);
- debug(F101,"zoutdump write returns","",x);
- zoutcnt = 0; /* Reset output buffer count */
- return(-1); /* write() failed */
- }
- }
-
-
- /* C H K F N -- Internal function to verify file number is ok */
- /*
- Returns:
- -1: File number n is out of range
- 0: n is in range, but file is not open
-
- 1: n in range and file is open
- */
- chkfn(n) int n; {
- switch (n) {
- case ZCTERM:
- case ZSTDIO:
- case ZIFILE:
- case ZOFILE:
- case ZDFILE:
- case ZTFILE:
- case ZPFILE:
- case ZSFILE:
- case ZSYSFN:
- case ZRFILE:
- case ZWFILE: break;
- default:
- debug(F101,"chkfn: file number out of range","",n);
- fprintf(stderr,"?File number out of range - %d\n",n);
- return(-1);
- }
- return( (fp[n] == NULL) ? 0 : 1 );
- }
-
- /* Z C H K I -- Check if input file exists and is readable */
-
- /*
- Returns:
- >= 0 if the file can be read (returns the size).
- -1 if file doesn't exist or can't be accessed,
- -2 if file exists but is not readable (e.g. a directory file).
- -3 if file exists but protected against read access.
- */
- /*
- For Berkeley Unix, a file must be of type "regular" to be readable.
- Directory files, special files, and symbolic links are not readable.
- */
- long
- zchki(name) char *name; {
-
- /* For some reason, the DG croaks intermittently with a call to stat(),
- * and goes into an infinite loop. This routine needs to see if the
- * file is okay to look at and access, so I will just call ?fstat to
- * do that. The only files that cannot be accessed by normal i/o routines
- * are directories. Other files are fair game.
- */
-
- int x; long y;
- P_FSTAT buf; /* struct stat buf; */
- int ac0,ac2;
- char * temp; /* ENH - in case we have to prepend an = */
- /* because ?fstat looks in searchlist */
- temp = alloc (strlen(name)+2);
- if ((*name != '^') && (*name != '@') && (*name != ':') && (*name != '=')) {
- strcpy (temp+1,name);
- *temp = '=';
- }
- else
- strcpy (temp,name);
-
- ac0 = (int) temp; ac2 = (int) &buf;
- x = sys_fstat(ac0,0,ac2);
-
- free(temp);
- if (x != 0) {
- debug(F111,"zchki sys_fstat fails",name,ac0);
- return(-1);
- }
- x = buf.styp_type; /* Isolate file format field */
- iflen = buf.sefm;
-
- if ((x >= $LDIR) && (x <= $HDIR)) {
- debug(F111,"zchki skipping DIR type:",name,x);
- return(-2);
- }
-
- debug(F111,"zchki stat ok:",name,x);
-
- if ((x = access(name,R_OK)) < 0) { /* Is the file accessible? */
- debug(F111," access failed:",name,x); /* No */
- return(-3);
- } else {
- y = buf.sefm;
- debug(F111," access ok:",name,(int) y); /* Yes */
- return( (y > -1) ? y : 0 );
- }
- }
-
- /* Z C H K O -- Check if output file can be created */
-
- /*
- Returns -1 if write permission for the file would be denied, 0 otherwise.
- */
- zchko(name) char *name; {
- int i, x;
- char s[50], *sp;
-
- sp = s; /* Make a copy, get length */
- x = 0;
- while ((*sp++ = *name++) != '\0')
- x++;
- if (x == 0) return(-1); /* If no filename, fail. */
-
- debug(F101," length","",x);
- for (i = x; i > 0; i--) /* Strip filename. */
- if (ISDIRSEP(s[i-1])) break;
-
- debug(F101," i","",i);
- if (i == 0) /* If no path, use current directory */
- strcpy(s,"=");
- else /* Otherwise, use given one. */
- s[i] = '\0';
-
- x = access(s,W_OK); /* Check access of path. */
- if (x < 0) {
- debug(F111,"zchko access failed:",s,errno);
- return(-1);
- } else {
- debug(F111,"zchko access ok:",s,x);
- return(0);
- }
- }
-
- /* Z D E L E T -- Delete the named file. */
-
- zdelet(name) char *name; {
- if (*name == '\0') {
- debug(F111,"zdelet passed null filename","",0);
- return(-1);
- }
- return(unlink(name));
- }
-
-
- /* Z R T O L -- Convert remote filename into local form */
-
- /* For AOS/VS, we don't care about case -- we only care about certain chars */
-
- zrtol(name,name2) char *name, *name2; {
- char *p; int flag;
- if (!name || !name2)
- return;
- debug(F110,"zrtol original name ",name,0);
- p = name2; /* Output pointer to new name */
- for ( ; *name != '\0'; name++) {
- if (*name > ' ') flag = 1; /* Strip leading blanks and controls */
- if (flag == 0 && *name < '!')
- continue;
- if (*name == '-') *p = '_'; /* Change dash to underscore */
- else if (*name == '^' || /* Change template characters to 'X' */
- *name == '*' ||
- *name == '+' ||
- *name == '#' ||
- *name == '\\' )
- *p = 'X';
- else *p = *name; /* Other characters are just copied */
- p++;
- }
- *p-- = '\0'; /* Terminate */
- while (*p < '!' && p > name2) /* Strip trailing blanks & controls */
- *p-- = '\0';
- if (*name2 == '\0') strcpy(name2,"NONAME");
- debug(F110,"zrtol translated name ",name2,0); /* Done */
- }
- /* Z S T R I P -- Strip device & directory name from file specification */
-
- /* Strip pathname from filename "name", return pointer to result in name2 */
-
- static char work[257]; /* buffer for use by zstrip and zltor */
-
- VOID
- zstrip(name,name2) char *name, **name2; {
- char *cp, *pp, *p2;
- debug(F110,"zstrip before",name,0);
- pp = work;
-
- for (cp = name; *cp != '\0'; cp++) {
- if (ISDIRSEP(*cp))
- pp = work;
- else
- *pp++ = *cp;
- }
- *pp = '\0'; /* Terminate the string */
- *name2 = work;
- debug(F110,"zstrip after",*name2,0);
- }
-
- /* Z L T O R -- Local TO Remote */
-
- /* Convert filename from local format to common (remote) form. */
-
- VOID
- zltor(name,name2) char *name, *name2; {
- char work[100], *cp, *pp;
- int dc = 0;
-
- debug(F110,"zltor",name,0);
- pp = work;
- /* Strip off the DG directory prefix */
- for (cp=name; *cp != '\0'; cp++) {
- if (ISDIRSEP(*cp)) {
- dc = 0;
- pp = work;
- }
- else if (islower(*cp)) *pp++ = toupper(*cp); /* Uppercase letters */
- else if (*cp == '~') *pp++ = 'X'; /* Change tilde to 'X' */
- else if (*cp == '#') *pp++ = 'X'; /* Change number sign to 'X' */
- else if (*cp == '$') *pp++ = 'X'; /* Change dollar sign to 'X' */
- else if (*cp == '?') *pp++ = 'X'; /* Change question mark to 'X' */
- else if ((*cp == '.') && (++dc > 1)) *pp++ = 'X'; /* & extra dots */
- else *pp++ = *cp;
- }
- *pp = '\0'; /* Tie it off. */
- cp = name2; /* If nothing before dot, */
- if (*work == '.') *cp++ = 'X'; /* insert 'X' */
- strcpy(cp,work);
- debug(F110," name2",name2,0);
- }
-
-
- /* Z C H D I R -- Change directory */
-
- zchdir(dirnam) char *dirnam; {
- char *hd;
- if (*dirnam == '\0') hd = getenv("HOME");
- else hd = dirnam;
- return((chdir(hd) == 0) ? 1 : 0);
- }
-
- /* Z H O M E -- Return pointer to user's home directory */
-
- char *
- zhome() {
- char *result,*ptr;
- static char *buf;
- static int homeflag = 0;
-
- if (homeflag) return (buf); /* if homeflag, result already */
- result = (getenv("HOME")); /* in buf - don't do it again */
- if (result != NULL) {
- buf = malloc (strlen (result) + 2); /* 1 for null, 1 for final : */
- if (buf == NULL) {
- debug(F111,"zhome can't allocate memory","",0);
- return(NULL);
- }
- for (ptr = buf ; *result != '\0'; ptr++,result++)
- if (*result == '/')
- *ptr = DIRSEP;
- else
- *ptr = toupper(*result);
- *ptr++ = DIRSEP;
- *ptr = '\0';
- homeflag = 1;
- }
- return(buf);
- }
-
- /* Z G T D I R -- Return pointer to user's current directory */
-
- #ifdef MAXPATH
- #define CWDBL MAXPATH
- #else
- #define CWDBL 100
- #endif
-
- static char cwdbuf[CWDBL+1];
-
- char *
- zgtdir() {
- char *buf;
- int error;
- buf = cwdbuf;
- if ((error = get_dir(buf)) != 0) {
- debug(F111,"zgtdir can't get dir name, VS error","",error);
- return(NULL);
- }
- else
- return(buf);
- }
-
- /*********************************************************************
- P I P E _ C A L L
-
- Split off the arguments from a command to the system, and
- pass the command and arguments to the system routine.
- Return the name of the temp file which stored the results of the
- command.
- This routine assumes that the "l=" option is available on all
- commands, which is true of AOS/VS CLI. Other DG systems may need
- another method, if the l= option is not available.
-
- Returns 0 if the system() function succeeds (>1 status)
- 1 if the system() function fails.
-
- I would have deleted this routine, except that I use it in zxpand()
- if a # is used as a wild card character. I used to depend on this
- routine for zxcmd() as well as zxpand(), but I now use sys_proc and
- sys_gnfn() respectively.
-
- *********************************************************************/
-
- int pipe_call(command,output_fname)
- char *command,output_fname[];
- {
- /* Look for the first semi-colon, if any, and strip up to that point, plus
- any blanks following it. Because the system() command refers to
- the initial working directory, a "dir xxx;" is usually pre-pended.
- */
- char *arguments, syscommand[512], locommand[512];
- char *insert,*fname,*cp,*tempname;
- FILE *dummy;
-
- strcpy(locommand,command);
- /* Find the first ;, if any */
- for (insert=locommand; ((*insert) && (*insert!=';')); insert++);
- if (*insert) arguments = insert+1;
- else arguments = locommand; /* No ; found */
- /* Skip leading spaces */
- for (; ((*arguments) && isspace(*arguments)); arguments++);
- /* Find the end of the command to CLI */
- for (; ((*arguments) && (*arguments!=',') && !isspace(*arguments));
- arguments++);
- /* If *arguments is NULL, there are no parameters to the command.
- Otherwise, null-terminate command and address the arguments */
- if (*arguments) *arguments++ = '\0';
-
- /* create the @OUTPUT file name -- a unique file name */
- fname = getenv("HOME");
- for (cp=fname; *cp; cp++) if (*cp == '/') *cp=':';
- strcpy(syscommand,fname); strcat(syscommand,":?kermit_pipe_123456");
- fname = &syscommand[0];
- mktemp(fname);
- strcpy(output_fname,fname);
-
- /* Create the file to establish its file type first */
- close(dummy=open(output_fname,O_WRONLY));
-
- /* Append an L= (listing =) switch. All CLI commands have this. */
- sprintf(syscommand,"%s/l=%s%s",locommand,output_fname,arguments);
- debug(F101,"syscommand",syscommand,0);
- /* now execute the command */
- if (system(syscommand) > 1) {
- perror("system");
- return(1);
- }
- return(0);
- }
-
-
- /* Z X C M D -- Run a system command so its output can be read like a file */
-
- zxcmd(filenum,comand) int filenum; char *comand; {
- /******** Start of Rick Lamb's addition to Kermit history. ****************/
- /* I modified Rick's code to use a tempname type of file. -- Phil Julian. */
- /* Can open and start a task in AOS using their dg_open command
- * and a system call "sys_proc" in "start_cli". R.H.Lamb 12/86
- */
- FILE *piped;
- char temp[256];
- char *tempfile,*cp,pipename[256];
- char *shell, *savep, *comand2;
- int i;
-
- /* Create a unique pipe file in the users home directory, because
- * the actual working directory could be where the user has no
- * write privelages, or two users may collide in the same directory.
- */
- debug(F000,"Entering zxcmd","",0);
- if (chkfn(filenum) < 0) return(-1);
- tempfile = getenv("HOME");
- for (cp = tempfile; *cp; cp++) if (*cp == '/') *cp=':';
- /* Make sure and copy the NULL also */
- memcpy (pipename, tempfile, strlen(tempfile)+1);
- strcat (pipename,":?kermit_pipe_123456");
- mktemp(pipename);
-
- /* The command interpreter for AOS is "cli.pr"
- * for MV/UX its :bin:sh:pr
- */
- if ((piped=dg_open(pipename,$ICRF+$OFIN+$OFCR+$RTDY,$FPIP))==NULL) {
- perror("Trouble creating a pipe in zxcmd\n");
- fprintf(stderr,"Pipe filename was [%s]\n",pipename);
- return(0);
- }
- debug(F000," pipe file created","",0);
- debug(F110," zxcmd: received command = ",comand,0);
-
- savep = strchr(comand,' '); /* enh - find blank and if there */
- if (savep != NULL) { /* is one, split comand in 2 */
- *savep = '\0';
- comand2 = ++savep; /* comand2 points to 1st arg */
- } else comand2 = NULL; /* we're doing all this so we can */
- debug(F110," zxcmd: command = ",comand,0); /* put the L= switch on*/
- if (comand2 != NULL) /* the command rather than the proc */
- debug(F110," zxcmd: arguments = ",comand2,0);
- else
- debug(F110," zxcmd: arguments = none","",0);
- #ifdef mvux
- shell = ":bin:sh.pr";
- #else
- shell = ":cli.pr";
- #endif
- if (comand2 != NULL)
- sprintf(temp,"%s,%s/L,%s",shell,comand,comand2);
- else
- sprintf(temp,"%s,%s/L",shell,comand);
-
- debug(F110," zxcmd: revised command = ",temp,0);
-
- if (start_cli(temp,pipename))
- {perror("Can't execute command in zxcmd\n"); return(0);}
- fp[filenum]=piped;
- fp[ZSYSFN]=fp[filenum];
- zincnt = 0;
- zinptr = zinbuffer;
- return(1);
- }
-
- #ifdef SASMOD
-
- /* For remote Kermit command */
- /* Z X L O G -- redirect stderr and stdout for logging. */
-
- zxlog() {
- FILE *tmpf, *tmpfile();
-
- if (chkfn(ZSYSFN) != 0) return(0);
- /* Unix magic to redirect stdout and stderr to temporary file */
- fflush(stdout); fflush(stderr); /* synchronize */
- if ((tmpf = tmpfile()) == NULL) return(0);
- if ((savout = dup(1)) < 0 || (saverr = dup(2)) < 0) return(0);
- dup2(fileno(tmpf), 1); dup2(fileno(tmpf), 2);
- fp[ZSYSFN] = tmpf;
- return(1);
- }
-
-
- /* Z X U N L O G -- restore stderr and stdout from logging. */
-
- zxunlog() {
- /* restore stdout and stderr */
- fflush(stdout); fflush(stderr); /* synchronize */
- dup2(savout, 1); close(savout);
- dup2(saverr, 2); close(saverr);
-
- /* rewind to start of temporary file */
- rewind(fp[ZSYSFN]);
-
- fp[ZIFILE] = fp[ZSYSFN];
- pid = 0;
- return(1);
- }
-
- #endif SASMOD
-
- /* Z C L O S F - wait for the child fork to terminate and close the pipe. */
-
- zclosf() {
- int wstat;
- fclose(fp[ZIFILE]);
- fp[ZIFILE] = fp[ZSYSFN] = NULL;
- while ((wstat = wait(0)) != pid && wstat != -1) ;
- return(1);
- }
-
-
- /******** More of Rick Lamb's addition to Kermit history. */
-
- /* S T A R T _ C L I - starts a command as another concurrent task.
- * The command is equivalent to the CLI command of
- * "proc/def/output=pipename :cli command"
- */
- start_cli(command,pipename)
- char *command,*pipename;
- {
-
- P_PROC packet;
- P_ISEND message;
- int len,pid,err;
- short int *string = (short int *)command;
-
- debug(F110,"Start_cli: command = ",command,0);
-
- len = strlen(command);
-
- message.isfl = (short) 0; /* System flags */
- message.iufl = (short) $RFCF; /* User flags */
- message.idph = (long) 0; /* Destination port number */
- message.iopn = (short) 0; /* Local origin port number */
- message.ilth = (short) (len / 2 + 1); /* Length (in words) of message */
- message.iptr = string; /* Pointer to message buffer */
-
- packet.pflg = (short) 0; /* Flags for process creation */
- packet.ppri = (short) -1; /* Process priority -- was 3 */
- packet.psnm = ":cli.pr"; /* Byte pointer to program name */
- packet.pipc = &message; /* Pointer to initial msg. or -1 */
- packet.pnm = (char *) -1; /* Byte ptr to process name or -1 */
- packet.pmem = (long) -1; /* Maximum memory pages or -1 */
- packet.pdir = (char *) 0; /* Byte ptr to initial dir. or -1/0 */
- packet.pcon = (char *) 0; /* Byte ptr to console name or -1/0 */
- packet.pcal = (short) -1; /* Max concurrent system calls or -1 */
- packet.pwss = (short) -1; /* Max working set size or -1 */
- packet.punm = -1; /* Byte ptr to username or -1 */
- /* Note that $PVPC (unlimited sons) causes privelage violations
- * for users that are not royally endowed. Anyway, following are
- * the privileges bits. -- Phil Julian
- */
- packet.pprv = (short) ( /* $PVPC+ */ $PVWS+$PVEX+$PVIP);
- packet.ppcr = (short) -1; /* Maximum sons or -1 */
- packet.pwmi = (short) -1; /* Working set minimum or -1 */
- /* reserved */
- packet.pifp = "@Null"; /* Byte ptr to @INPUT or -1/0 */
- packet.pofp = "@Null"; /* Byte ptr to @OUTPUT or -1/0 */
- packet.plfp = pipename; /* Byte ptr to @LIST or -1/0 */
- packet.pdfp = (char *) 0; /* Byte ptr to @DATA or -1/0 */
- packet.smch = (_ulong) -1; /* Max CPU time or -1 */
-
- if (err = sys_proc(&packet,&pid)) {
- perror("Start_cli: sys_proc ");
- fprintf(stderr,"Start_cli: Error in sys_proc = %#o\n",err);
- return(1);
- }
- else
- return(0);
- }
- /******** End of Rick Lamb's addition to Kermit history. */
-
-
- /* Z X P A N D -- Expand a wildcard string into an array of strings */
- /*
- Returns the number of files that match fn1, with data structures set up
- so that first file (if any) will be returned by the next znext() call.
- */
- zxpand(fn) char *fn; {
-
- /* Victor Johansen's code requires no change in zxpand().
- * However, it is difficult to expand wild card strings that
- * contain some ^ or #. For a #, you must check the file type for
- * being a directory, then open up the directory, and keep searching
- * for sub-directories, etc. However, an simple kludge can be used
- * in this case, which saves me the programming effort. Anyone
- * using the # should pay an execution time penalty for using it.
- * So when a string contains the #, we use the original kludge that
- * I used before getting Victor's code. Victor Johansen's code is more
- * efficient because it uses sys_gnfn(), but I have to do more work
- * in some cases. With the ^'s, the directory name must be parsed
- * and adjusted, before opening the correct directory.
- */
-
- char tempname[256],command[256];
- int pipe_call();
- FILE *sysout;
- char *curptr, *saveptr, buffer[257], *pos, *end;
- int n;
-
- wildcarlb = 0;
- for (curptr = fn; *curptr; curptr++)
- if (*curptr == '#') { wildcarlb = 0; goto nonvictor; }
- wildcarlb = 1; goto victor;
-
- nonvictor:
- curptr = command;
- sprintf(curptr, "filestatus/cpl=16/nheader %s", fn);
- curptr = tempname;
- pipe_call(command,curptr);
-
- /* Read the file of filenames, and parse out a universal name */
- sysout = fopen(tempname,"r");
- for (fcount=0; n=dg_fgets(buffer,256,sysout); )
- {
- curptr = (char *) malloc(min(256,strlen(buffer)));
- mtchs[fcount]=curptr;
- /* delete leading spaces, leading directory name, and and trailing LF */
- if (iscntrl(*(pos = &buffer[strlen(buffer)-1])))
- *pos-- = '\0';
- /* First char will be =, if working dir, or : or @ if not.
- Delete the =, but keep others.
- */
- for (pos=buffer; *pos; pos++) {
- if (*pos == '=') break;
- if ((*pos == ':') || (*pos == '@')) { pos--; break; }
- }
- strcpy(mtchs[fcount],pos+1);
- fcount++;
- }
- fclose(sysout);
- zdelet(tempname);
-
- victor:
- if (wildcarlb)
- fcount = fgen(fn,mtchs,MAXWLD); /* Look up the file. */
-
- if (fcount > 0) {
- mtchptr = mtchs; /* Save pointer for next. */
- }
- debug(F111,"zxpand",mtchs[0],fcount);
- return(fcount);
- }
-
-
-
- /* Z N E X T -- Get name of next file from list created by zxpand(). */
- /*
- Returns >0 if there's another file, with its name copied into the arg string,
- or 0 if no more files in list.
- */
- znext(fn) char *fn; {
- if (fcount-- > 0)
- {
- /* Victor Johansen's code requires no change in znext(), but my
- * code does. The flag, wildcardlb is 1, if Victor's code is
- * in effect.
- */
- strcpy(fn,*mtchptr++);
- if (wildcarlb == 0) /* My old code: Phil Julian */
- free (*(mtchptr-1));
- }
- else *fn = '\0';
- debug(F111,"znext",fn,fcount+1);
- return(fcount+1);
- }
-
- /* Z C H K S P A -- Check if there is enough space to store the file */
-
- /*
- Call with file specification f, size n in bytes.
- Returns -1 on error, 0 if not enough space, 1 if enough space.
- */
- int
- zchkspa(f,n) char *f; long n; { /* ENH - this is not feasible in VS */
- return(1); /* where the space returned is an */
- } /* allocation limit rather than a */
- /* physical one - so always return 1*/
-
- /* Z N E W N -- Make a new name for the given file */
-
- znewn(fn,s) char *fn, **s; {
- static char buf[100];
- #define ZNEWNMD 4 /* Max digits for version number */
- char *bp, *xp;
- int len = 0, n = 0, d = 0, t, i, power = 1;
- int j, k;
- int max = MAXNAMLEN;
-
- bp = buf;
- while (*fn) { /* Copy name into buf */
- *bp++ = *fn++;
- len++;
- }
- if (len > max-2) { /* Don't let it get too long */
- bp = buf + max-2;
- len = max - 2;
- }
-
- for (i = 1; i < (ZNEWNMD - 1); i++) {
- power *= 10;
- *bp++ = '+';
- *bp-- = '\0';
-
- n = zxpand(buf); /* Expand the resulting wild name */
-
- while (n-- > 0) { /* Find any existing name~d files */
- xp = *mtchptr++;
- xp += len;
- if (*xp == '.') {
- t = atoi(xp+1);
- if (t > d) d = t; /* Get maximum d */
- }
- }
- if (d < power-1) {
- sprintf(bp,".%d",d+1); /* Make name~(d+1) */
- *s = buf;
- return;
- }
- bp--; len--;
- }
- /* If we ever get here, we'll overwrite the xxx~100 file... */
- }
-
- #ifndef NOFRILLS
-
- int
- zmail(p,f) char *p, *f; { /* Send f as mail to addr p */
- /*
- Returns 0 on success
- 2 if mail delivered but temp file can't be deleted
- -2 if mail can't be delivered
- The UNIX version always returns 0 because it can't get a good return
- code from zsyscmd.
-
- *zmbuf = '\0'; /* Not implemented in AOS/VS Kermit */
- return(-2);
- }
- #endif /* NOFRILLS */
-
- #ifndef NOFRILLS
- int
- zprint(p,f) char *p; char *f; { /* Print file f with options p */
-
- sprintf(zmbuf,"qprint%s %s",p,f); /* ENH - options must be specified */
- zsyscmd(zmbuf); /* by user as /<option>/<option>.. */
- return(0);
- }
- #endif /* NOFRILLS */
-
- /* Z R E N A M E -- changes the name of old to new */
- /*
- Returns -1 on failure, 0 on success
- */
- zrename(old,new) char *old, *new; {
- int ac0,ac1,ac2,result;
-
- ac0 = (char *) old;
- ac1 = (char *) new;
- ac2 = 0;
-
- result = sys($RENAME,&ac0,&ac1,&ac2);
- if (result > 0) {
- debug(F110," rename fails",old,result); /* last arg is zero in unix */
- return(-1); /* - using result may not */
- } /* work */
- if (result < 0) {
- debug (F110," negative return from rename system call",old,result);
- return(-1);
- }
- return(0);
- }
-
- /* Z F C D A T -- Get file creation date */
- /*
- Call with pointer to filename.
- On success, returns pointer to creation date in yyyymmdd hh:mm:ss format.
- On failure, returns pointer to null string.
- */
- static char datbuf[40];
-
- /* static */ /* (===OS2 change===) */
- char *
- zfcdat(name) char *name; {
-
- #ifdef TIMESTAMP
-
- P_FSTAT fs_pak; /* for AOS/VS only */
- int year,month,day,hours,minutes,seconds;
- int error;
- int ac0,ac1,ac2; /* registers for fstat system call */
- long date;
-
- ac0 = name; /* ptr to filename */
- ac1 = 0; /* resolve links */
- ac2 = (P_FSTAT *) &fs_pak;
- error = sys ($FSTAT, &ac0, &ac1, &ac2); /* get modification date */
- if (error != 0) {
- debug(F110,"zfcdat stat failed",name,error);
- return("");
- }
-
- date = fs_pak.stmh.long_time; /* last modification date in seconds */
- error = dg_date(fs_pak.stmh.short_time[_DATE],&day,&month,&year);
- if (error != 0) {
- debug(F110,"zfcdat call to dg_date() failed","",error);
- return("");
- }
- error = dg_time(fs_pak.stmh.short_time[_TIME],&hours,&minutes,&seconds);
- if (error != 0) {
- debug(F110,"zfcdat call to dg_time() failed","",error);
- return("");
- }
- if (year < 100)
- year += 1900;
- if (year < 0 || year > 2100) { /* Make sure year is ok */
- debug(F110,"zfcdat date failed",name,0);
- return("");
- }
- if (month < 1 || month > 12)
- return("");
- if (day < 0 || day > 31)
- return("");
- if (hours < 0 || hours > 23)
- return("");
- if (minutes < 0 || minutes > 59)
- return("");
- if (seconds < 0 || seconds > 59)
- return("");
- sprintf(datbuf,"%04d%02d%02d %02d:%02d:%02d",year,month,day,hours,
- minutes,seconds);
- debug(F111,"zfcdat",datbuf,strlen(datbuf));
- return(datbuf);
-
- #else
- return ("");
- #endif /* timestamp */
- }
-
- /* Z S T I M E -- Set creation date for incoming file */
- /*
- Call with:
- f = pointer to name of existing file.
- yy = pointer to a Kermit file attribute structure in which yy->date.val
- is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
- x = is a function code: 0 means to set the file's creation date as given.
- 1 means compare the given date with the file creation date.
- Returns:
- -1 on any kind of error.
- 0 if x is 0 and the file date was set successfully.
- 0 if x is 1 and date from attribute structure <= file creation date.
- 1 if x is 1 and date from attribute structure > file creation date.
- */
-
- int
- zstime(f,yy,x) char *f; struct zattr *yy; int x; {
- int r = -1; /* return code */
- int error;
- long tm; /* UNIX scalar form of date/time */
- char myname[] = "zstime()";
- long validate();
- int vs_existing_datetime, vs_incoming_datetime;
- char existing_kdate[20], *incoming_kdate = yy->date.val;
- void convert_kdate_to_aosvs(),convert_aosvs_to_kdate();
-
- if ((x != 0) && (x != 1)) {
- debug(F111,"Bad argument",yy->date.val,yy->date.len);
- return (-1);
- }
- tm = validate(yy,myname); /* tm not used unless error */
- if (tm == -1) {
- debug(F111,"zstime fails on date check",incoming_kdate,yy->date.len);
- return (-1);
- }
- if ( error = fs_get_modification_date (f,&vs_existing_datetime) ) {
- debug(F110,"Can't stat file:",f,0);
- return(-1);
- }
- debug(F111,"zstime FSTAT of existing file okay",f,vs_existing_datetime);
- convert_kdate_to_aosvs(incoming_kdate,&vs_incoming_datetime);
- debug(F111,"zstime date of incoming file","",vs_incoming_datetime);
-
- /* ENH - modified for VS - we set the creation date in zopeno() */
- /* because the only straightforward way of setting it in VS is on the */
- /* create; so, if x is 0 here we don't do anything */
-
- switch (x) { /* Execute desired function */
- case 0: /* Set the creation date of the file */
- debug(F110,"VS creation date intentionally not set in zstime(): ",f,0);
- r = 0;
- break;
- case 1: /* Compare the dates */
- convert_aosvs_to_kdate(existing_kdate,vs_existing_datetime);
- debug(F111,"zstime compare existing file date",existing_kdate,0);
- debug(F111,"zstime compare incoming file date",incoming_kdate,0);
- if (vs_incoming_datetime < vs_existing_datetime) r = 1; else r = 0;
- break;
- default: /* Error */
- r = -1;
- }
- return (r);
- }
-
-
- /* Z S A T T R -- fills in Kermit file attribute structure */
- /*
- Returns 0 on success or -1 on falure. Any string members that are null
- should be ignored by the caller; likewise, any numeric members that are
- -1 should be ignored. (Actually, there is no error return right now.)
- */
- int
- zsattr(xx) struct zattr *xx; {
- long k;
-
- if (iflen > 0)
- k = iflen % 1024L; /* file length in k bytes */
- else k = 0L;
- if (k != 0L) k = 1L;
- xx->lengthk = (iflen / 1024L) + k;
- xx->type.len = 0; /* file type can't be filled in here */
- xx->type.val = "";
- if (*nambuf) {
- xx->date.val = zfcdat(nambuf); /* File creation (mod. in VS) date */
- xx->date.len = (int)strlen(xx->date.val);
- } else {
- xx->date.len = 0;
- xx->date.val = "";
- }
- xx->creator.len = 0; /* File creator */
- xx->creator.val = "";
- xx->account.len = 0; /* File account */
- xx->account.val = "";
- xx->area.len = 0; /* File area */
- xx->area.val = "";
- xx->passwd.len = 0; /* Area password */
- xx->passwd.val = "";
- xx->blksize = -1L; /* File blocksize */
- xx->access.len = 0; /* File access */
- xx->access.val = "";
- xx->encoding.len = 0; /* Transfer syntax */
- xx->encoding.val = 0;
- xx->disp.len = 0; /* Disposition upon arrival */
- xx->disp.val = "";
- xx->lprotect.len = 0; /* Local protection */
- xx->lprotect.val = "";
- xx->gprotect.len = 0; /* Generic protection */
- xx->gprotect.val = "";
- xx->systemid.len = 2; /* System ID */
- xx->systemid.val = "U1";
- xx->recfm.len = 0; /* Record format */
- xx->recfm.val = "";
- xx->sysparam.len = 0; /* System-dependent parameters */
- xx->sysparam.val = "";
- xx->length = iflen; /* Length */
- return(0);
- }
-
-
-
- /* Directory Functions for Unix, written by Jeff Damens, CUCCA, 1984. */
-
- /*
- * The path structure is used to represent the name to match.
- * Each slash-separated segment of the name is kept in one
- * such structure, and they are linked together, to make
- * traversing the name easier.
- */
-
- struct path {
- char npart[MAXNAMLEN]; /* name part of path segment */
- struct path *fwd; /* forward ptr */
- };
-
- #define SSPACE 10000 /* size of string-generating buffer */
- static char sspace[SSPACE]; /* buffer to generate names in */
-
- static char *freeptr,**resptr; /* copies of caller's arguments */
- static int remlen; /* remaining length in caller's array*/
- static int numfnd; /* number of matches found */
-
- /*
- * splitpath:
- * takes a string and splits the slash-separated portions into
- * a list of path structures. Returns the head of the list. The
- * structures are allocated by malloc, so they must be freed.
- * Splitpath is used internally by the filename generator.
- *
- * Input: A string.
- * Returns: A linked list of the slash-separated segments of the input.
- */
-
- struct path *
- splitpath(p)
- char *p;
- {
- struct path *head,*cur,*prv;
- int i;
- head = prv = NULL;
- if (*p == '/') p++; /* skip leading slash */
- while (*p != '\0')
- {
- cur = (struct path *) malloc(sizeof (struct path));
- debug(F101,"splitpath malloc","",cur);
- if (cur == NULL) fatal("malloc fails in splitpath()");
- cur -> fwd = NULL;
- if (head == NULL) head = cur;
- else prv -> fwd = cur; /* link into chain */
- prv = cur;
- for (i=0; i < MAXNAMLEN && *p != '/' && *p != '\0'; i++)
- cur -> npart[i] = *p++;
- cur -> npart[i] = '\0'; /* end this segment */
- if (i >= MAXNAMLEN) while (*p != '/' && *p != '\0') p++;
- if (*p == '/') p++;
- }
- return(head);
- }
-
- /* F G E N -- finds filenames that match string */
- /*
- * fgen:
- * This is the actual name generator. It is passed a string,
- * possibly containing wildcards, and an array of character pointers.
- * It finds all the matching filenames and stores them into the array.
- * The returned strings are allocated from a static buffer local to
- * this module (so the caller doesn't have to worry about deallocating
- * them); this means that successive calls to fgen will wipe out
- * the results of previous calls. This isn't a problem here
- * because we process one wildcard string at a time.
- *
- * Input: a wildcard string, an array to write names to, the
- * length of the array.
- * Returns: the number of matches. The array is filled with filenames
- * that matched the pattern. If there wasn't enough room in the
-
- * array, -1 is returned.
- * By: Jeff Damens, CUCCA, 1984.
- */
-
- fgen(pat,resarry,len)
- char *pat,*resarry[];
- int len;
- {
- /* Victor Johannsen helped out with this addition to Kermit. The use of
- * sys_gnfn() is the proper way to solve this problem. But, I would prefer
- * not building up the static string space. This can be a problem when a
- * long, full-qualified directory name pattern is used, since this directory
- * name would be pre-pended to each file name.
- * A later fix would actually not build a list, but call sys_gnfn() within
- * znext(), and update the counters appropriately. Several systems support
- * this model, which seems much more flexible and not at all space-limited.
- * -- Phil Julian, 30 April 1987
- */
- P_GNFN packet; /* packet for gnfn call */
- char prefix[256];
- char dirname[256];
- int chan; /* Channel for open the DIR */
- FILE *Ftemp;
- char *DIRptr; /* DIR name */
- int i,off;
- int got_dir = 0;
- char *pattern,*cp;
-
- /* If a directory prefix is passed in, and possibly some wild cards, we
- * will need to parse off the directory to open. We do not assume that
- * directories can be descended ad infinitum.
- */
- i = strlen(pat); zero(prefix,min(i+1,256));
- for (cp = pat+i-1; i-- >= 0; cp--)
- if ((*cp == ':') || (*cp == '^') || (*cp == '=') || (*cp == '@')) {
- memcpy(prefix,pat,off = i+1);
- memcpy(dirname,prefix,off-1), dirname[off-1] = 0;
- DIRptr = dirname, pattern = cp+1;
- got_dir = 1;
- /* Parse ^ for moving up a directory */
- if (*pat == '^') {
- /* From the tail of the current dir, back up to : */
- char *kp,*dp;
- int pos = 0;
-
- i = strlen(dp = getdir()) - 1;
- for (kp = pat; *kp == '^'; kp++,i--,pos++)
- for (;dp[i] != ':';i--);
- i++;
- if (strlen(DIRptr)) { /* Less ^s */
- memcpy(prefix,DIRptr+pos,strlen(DIRptr)-pos);
- prefix[strlen(DIRptr)-pos] = 0; /* Terminate */
- } else prefix[0] = 0;
- memcpy(dirname,dp,i); /* The ^'d DIR */
- off -= pos;
- if (pos = strlen(prefix)) {
- memcpy(dirname+i,":",1); /* Dir separator */
- memcpy(dirname+i+1,prefix,pos); /* Rest of dir name */
- }
- dirname[i+off] = 0; /* Null terminate */
- memcpy(prefix,dirname,off = strlen(dirname));
- prefix[off] = ':'; prefix[++off] = 0;
- }
- break;
- }
-
- if (got_dir == 0) {
- DIRptr = getdir();
- pattern = pat;
- }
-
- if ( (Ftemp = fopen(DIRptr,"r")) == NULL) return(0);
- chan = fchannel(Ftemp);
-
- numfnd = 0;
- freeptr = sspace;
- resptr = resarry;
- remlen = len;
-
- packet.nfky = 0;
- packet.nftp = pattern;
- packet.nfnm = nambuf;
-
- while (i = !sys_gnfn(chan,&packet)) {
- if (got_dir == 0) addresult( nambuf );
- else {
- memcpy(prefix+off,nambuf,strlen(nambuf)+1);
- addresult( prefix );
- }
- }
-
- fclose(Ftemp);
-
- return(numfnd); /* and return the number of matches */
- }
-
- /* T R A V E R S E -- searches directory for matches */
- /* traverse:
- * Walks the directory tree looking for matches to its arguments.
- * The algorithm is, briefly:
- * If the current pattern segment contains no wildcards, that
- * segment is added to what we already have. If the name so far
- * exists, we call ourselves recursively with the next segment
- * in the pattern string; otherwise, we just return.
- *
- * If the current pattern segment contains wildcards, we open the name
- * we've accumulated so far (assuming it is really a directory), then read
-
- * each filename in it, and, if it matches the wildcard pattern segment, add
- * that filename to what we have so far and call ourselves recursively on the
- * next segment.
- *
- * Finally, when no more pattern segments remain, we add what's accumulated
- * so far to the result array and increment the number of matches.
- *
- * Input: a pattern path list (as generated by splitpath), a string
- * pointer that points to what we've traversed so far (this
- * can be initialized to "/" to start the search at the root
- * directory, or to "./" to start the search at the current
- * directory), and a string pointer to the end of the string
- * in the previous argument.
- * Returns: nothing.
- */
- traverse(pl,sofar,endcur)
- struct path *pl;
- char *sofar,*endcur;
- {
- int fd;
- struct direct dir_entry;
- struct direct *dirbuf = &dir_entry;
- struct stat statbuf;
- if (pl == NULL)
- {
- *--endcur = '\0'; /* end string, overwrite trailing / */
- addresult(sofar);
- return;
- }
- if (!iswild(pl -> npart))
- {
- strcpy(endcur,pl -> npart);
- endcur += (int)strlen(pl -> npart);
- *endcur = '\0'; /* end current string */
- if (stat(sofar,&statbuf) == 0) /* if current piece exists */
- {
- *endcur++ = DIRSEP;
- *endcur = '\0';
- traverse(pl -> fwd,sofar,endcur);
- }
- return;
- }
- /* cont'd... */
-
- /*...traverse, cont'd */
-
- /* segment contains wildcards, have to search directory */
- *endcur = '\0'; /* end current string */
- if (stat(sofar,&statbuf) == -1) return; /* doesn't exist, forget it */
- if ((statbuf.st_mode & S_IFDIR) == 0) return; /* not a directory, skip */
-
- if ((fd = open(sofar,O_RDONLY)) < 0) return; /* can't open, forget it */
- while ( read(fd,dirbuf,sizeof dir_entry) )
- {
- strncpy(nambuf,dirbuf->d_name,MAXNAMLEN); /* Get a null terminated copy!!! */
-
- nambuf[MAXNAMLEN] = '\0';
- if (dirbuf->d_ino != 0 && match(pl -> npart,nambuf)) {
- char *eos;
- strcpy(endcur,nambuf);
- eos = endcur + strlen(nambuf);
- *eos = '/'; /* end this segment */
- traverse(pl -> fwd,sofar,eos+1);
- }
- }
- close(fd);
- }
-
- /* A D D R E S U L T -- adds result string to result array */
- /*
- * addresult:
- * Adds a result string to the result array. Increments the number
- * of matches found, copies the found string into our string
- * buffer, and puts a pointer to the buffer into the caller's result
- * array. Our free buffer pointer is updated. If there is no
- * more room in the caller's array, the number of matches is set to -1.
- * Input: a result string.
- * Returns: nothing.
- */
-
- addresult(str)
- char *str;
- {
- int l;
- if (strncmp(str,"./",2) == 0) str += 2;
- if (--remlen < 0) {
- numfnd = -1;
- return;
- }
- l = strlen(str) + 1; /* size this will take up */
- if ((freeptr + l) > &sspace[SSPACE]) {
- numfnd = -1; /* do not record if not enough space */
- return;
- }
- strcpy(freeptr,str);
- *resptr++ = freeptr;
- freeptr += l;
- numfnd++;
- }
-
- /* Z S Y S C M D -- Supposed to execute a "system" command. */
- /*
- Code copied verbatim from zshcmd for now
- */
- int
- zsyscmd(s) char *s; {
-
- if (priv_chk()) return(1);
- if (*s == '\0') /* Interactive shell requested? */
-
- #ifdef mvux
- system("/bin/sh ");
- #else
- system("x :cli prefix Kermit_Baby:");
- #endif /* mvux */
-
- else /* Otherwise, */
- system(s); /* Best for aos/vs?? */
- return (0); /* Assume no errors */
- }
-
-
- /* Z S H C M D -- Start a CLI */
- int
- zshcmd(s) char *s; { /* ENH - new function */
-
- if (priv_chk()) return(1);
- if (*s == '\0') /* Interactive shell requested? */
-
- #ifdef mvux
- system("/bin/sh ");
- #else
- system("x :cli prefix Kermit_CLI:");
- #endif /* mvux */
-
- else /* Otherwise, */
- system(s); /* Best for aos/vs?? */
- return (0); /* Assume no errors */
- }
-
- /* I S W I L D -- Check if filespec is "wild */
- /*
- Returns 0 if it is a single file, 1 if it contains wildcard characters.
- Note: must match the algorithm used by match(), hence no [a-z], etc
- */
- int
- iswild(filespec)
- char *filespec;
- {
- char c; int x; char *p;
- if (wildxpand) {
- if ((x = zxpand(filespec)) > 1) return(1);
- p = malloc(MAXNAMLEN + 20);
- znext(p);
- x = (strcmp(filespec,p) != 0);
- free(p);
- return(x);
- } else {
- while ((c = *filespec++) != '\0')
- if (c == '*' || c == '?') return(1);
- return(0);
- }
- }
- /* M A T C H -- see if pattern matches string */
- /*
- * match:
- * pattern matcher. Takes a string and a pattern possibly containing
- * the wildcard characters '*' and '?'. Returns true if the pattern
- * matches the string, false otherwise.
- * by: Jeff Damens, CUCCA
-
- *
- * Input: a string and a wildcard pattern.
- * Returns: 1 if match, 0 if no match.
- */
-
- match(pattern,string) char *pattern,*string; {
- char *psave,*ssave; /* back up pointers for failure */
- psave = ssave = NULL;
- while (1) {
- for (; *pattern == *string; pattern++,string++) /* skip first */
- if (*string == '\0') return(1); /* end of strings, succeed */
- if (*string != '\0' && *pattern == '?') {
- pattern++; /* '?', let it match */
- string++;
- } else if (*pattern == '*') { /* '*' ... */
- psave = ++pattern; /* remember where we saw it */
- ssave = string; /* let it match 0 chars */
- } else if (ssave != NULL && *ssave != '\0') { /* if not at end */
- /* ...have seen a star */
- string = ++ssave; /* skip 1 char from string */
- pattern = psave; /* and back up pattern */
- } else return(0); /* otherwise just fail */
- }
- }
-
- /* C H E C K _ K E R M I T _ D A T E -- see if Kermit date is valid */
- /*
- This function is new in the VS version of Kermit only. It replaces code
- that was previously in-line in zstime() that checks the validity of the
- date found in an argument passed in, and if it's valid, converts it to a
- scalar, stored in tm, which is returned. It takes a second argument, which
- is the name of the calling function. This is there so that entries to
- log will report the accurate Kermit function. It returns the value of
- tm if the date is valid and a -1 if not. --ENH
- */
- long
- validate (yy,caller) struct zattr *yy; char *caller; {
- int r = -1; /* return code */
- long tm, days;
- int i, n, isleapyear;
- /* J F M A M J J A S O N D */
- /* 31 28 31 30 31 30 31 31 30 31 30 31 */
- static
- int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
- char s[5];
- struct stat sb;
-
- debug(F111,caller," calling validate()",0);
- if ((yy->date.len == 0)
- || (yy->date.len != 17)
- || (yy->date.val[8] != ' ')
- || (yy->date.val[11] != ':')
- || (yy->date.val[14] != ':') ) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- debug(F111,"Date check 1",yy->date.val,yy->date.len);
- for(i = 0; i < 8; i++) {
- if (!isdigit(yy->date.val[i])) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- }
- debug(F111,"Date check 2",yy->date.val,yy->date.len);
- i++;
-
- for (; i < 16; i += 3) {
- if ((!isdigit(yy->date.val[i])) || (!isdigit(yy->date.val[i + 1]))) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- }
- debug(F111,"Date check 3",yy->date.val,yy->date.len);
- debug(F100,"So far so good","",0);
-
- s[4] = '\0';
- for (i = 0; i < 4; i++) /* Fix the year */
- s[i] = yy->date.val[i];
-
- debug(F110,"year",s,0);
-
- n = atoi(s);
-
- debug(F111,"year",s,n);
-
- /* Previous year's leap days. This won't work after year 2100, */
- /* I don't care about that! */
-
- isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
- days = (long) (n - 1970) * 365;
- days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
-
- s[2] = '\0';
-
- for (i = 4 ; i < 16; i += 2) {
- s[0] = yy->date.val[i];
- s[1] = yy->date.val[i + 1];
- n = atoi(s);
- debug(F110,"zstime entering switch",s,0);
- switch (i) {
- case 4: /* MM: month */
- if ((n < 1 ) || ( n > 12)) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- days += monthdays [n];
- if (isleapyear && n > 2)
- ++days;
- continue;
-
- case 6: /* DD: day */
- if ((n < 1 ) || ( n > 31)) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm = (days + n - 1) * 24L * 60L * 60L;
- i++; /* Skip the space */
- continue;
-
- case 9: /* hh: hour */
- if ((n < 0 ) || ( n > 23)) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm += n * 60L * 60L;
- i++; /* Skip the colon */
- continue;
-
- case 12: /* mm: minute */
- if ((n < 0 ) || ( n > 59)) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm += n * 60L;
- i++; /* Skip the colon */
- continue;
-
- case 15: /* ss: second */
- if ((n < 0 ) || ( n > 59)) {
- debug(F111,"Bad creation date ",yy->date.val,yy->date.len);
- return(-1);
- }
- tm += n;
- }
-
- if (localtime(&tm)->tm_isdst)
- tm -= 60L * 60L; /* Adjust for daylight savings time */
- }
-
- debug(F111,"Attribute creation date ok ",yy->date.val,yy->date.len);
-
- return(tm);
- }
-
- /* F I L E _ E X I S T S -- returns zero if filename already exists */
- /*
- Takes a pointer to a filename as an argument and determines whether that
- file exists. Returns 1 if it does, 0 if not, -1 on other error.
- */
- int
- file_exists(name) char *name; {
-
- P_FSTAT fs_pak;
- int ac0,ac1,ac2,error;
-
- ac0 = name;
- ac1 = 0; /* resolve links */
- ac2 = (P_FSTAT *) &fs_pak;
- error = sys($FSTAT,&ac0,&ac1,&ac2);
- if (error == ERFDE) /* file doesn't exist */
- return (0);
- if (error == 0) /* file does exist */
- return (1);
- else /* some other error */
- return (-1);
- }
-
-
- /* S E T _ C R E A T I O N _ D A T E -- set creation date on VS file */
- /*
- Takes a pointer to a filename and a timestamp in Kermit format and sets
- the creation date/time of the file -- returns 0 on success, -1 on failure
- */ /* Contributed by: */
- int /* Larry McCoskery, Data General */
- set_creation_date( filename, date_time )
- char * filename;
- char * date_time;
- {
- int ac0,ac1,ac2,error;
- int vs_datetime; /* VS scalar */
-
- P_CREATE crepak;
- P_CTIM timepak;
- void convert_kdate_to_aosvs();
-
- /*
- * First, convert the silly date. EH assures me that it's ok
- */
-
- convert_kdate_to_aosvs ( date_time, &vs_datetime);
-
- /*
- * Build the time packet. Set TCR, TLM, and TLA to specified date
- */
-
- timepak.tcth.long_time =
- timepak.tath.long_time =
- timepak.tmth.long_time = vs_datetime;
-
- /*
- * Build the create packet
- */
-
- crepak.cftyp_format = 0; /* record format */
- crepak.cftyp_entry = $FUDF; /* entry type */
- crepak.ccps = 0; /* file control parameters */
- crepak.ctim = &timepak; /* address of time block */
- crepak.cacp = -1; /* address of ACL */
- crepak.cdeh = 0; /* reserved */
- crepak.cdel = -1; /* file element size */
- crepak.cmil = -1; /* maximum index levels */
- crepak.cmrs = 0; /* reserved */
-
- /*
- * Create it
- */
-
- ac0 = (char *) filename;
- ac1 = 0; /* reserved */
- ac2 = (P_CREATE *) &crepak;
-
- error = sys( $CREATE, &ac0, &ac1, &ac2 );
-
- if( error != NULL ) {
- debug(F111, "can't create file - VS error",filename,error);
- error = -1; /* unix style "hide the error" */
- }
- else debug(F111,"file created",filename,0);
- return error;
- }
-
- void
- convert_kdate_to_aosvs( kermit_date, vs_scalar )
- char * kermit_date;
- int * vs_scalar;
- {
- int month, day, year, hour, minute, second;
- int date, time;
- char c;
- short * sp = vs_scalar;
-
- sscanf( kermit_date,"%4d%2d%2d%c%2d%c%2d%c%2d",
- &year,&month,&day,&c,&hour,&c,&minute,&c,&second );
-
- convert_date_to_dg( day, month, year, &date );
- convert_time_to_dg( hour, minute, second, &time );
-
- sp[0] = (short) date;
- sp[1] = (short) time;
- }
-
- void
- convert_aosvs_to_kdate( string, aosvs_scalar )
- char * string;
- int aosvs_scalar;
- {
- int day,month,year,hours,minutes,seconds;
- short * sp = &aosvs_scalar;
-
- dg_date( (int) sp[0], &day, &month, &year );
- dg_time( (int) sp[1], &hours, &minutes, &seconds );
-
- sprintf( string, "%4d%02d%02d %02d:%02d:%02d",
- year,month,day,hours,minutes,seconds );
- }
-
- int
- convert_date_to_dg( day, month, year, scalar )
- int day,month,year,*scalar;
- {
- int ac0,ac1,ac2,error;
-
- ac0 = day;
- ac1 = month;
- ac2 = year - 1900;
-
- error = sys( $FDAY, &ac0, &ac1, &ac2 );
-
- *scalar = ac0;
-
- return error;
- }
-
- int
- convert_time_to_dg( hours, mins, secs, scalar )
- int hours, mins, secs, *scalar;
- {
- int ac0,ac1,ac2,error;
-
- ac0 = secs;
- ac1 = mins;
- ac2 = hours;
-
- error = sys( $FTOD, &ac0, &ac1, &ac2 );
-
- *scalar = ac0;
-
- return error;
- }
-
- int
- dg_date( scalar, day, month, year )
- int scalar, *day, *month, *year;
- {
- int ac0,ac1,ac2,error;
-
- ac0 = scalar;
- ac1 = ac2 = 0;
- error = sys( $CDAY, &ac0, &ac1, &ac2 );
-
- *day = ac0;
- *month = ac1;
- *year = ac2 + 1900;
-
- return error;
- }
-
- int
- dg_time( scalar, hours, mins, secs )
- int scalar, *hours, *mins, *secs;
- {
- int ac0,ac1,ac2,error;
-
- ac0 = scalar;
- ac1 = ac2 = 0;
- error = sys( $CTOD, &ac0, &ac1, &ac2 );
-
- *hours = ac2;
- *mins = ac1;
- *secs = ac0;
-
- return error;
- }
-
- fs_get_modification_date( filename, date )
- char * filename;
- int * date;
- {
- P_FSTAT fs_pak;
- int ac0,ac1,ac2,error;
-
- ac0 = filename;
- ac1 = 0; /* resolve links */
- ac2 = (P_FSTAT *) &fs_pak;
- error = sys($FSTAT,&ac0,&ac1,&ac2);
-
- *date = fs_pak.stmh.long_time;
-
- return error;
- }
-
- int
- get_dir(dirbuf)
- char *dirbuf;
- {
- int ac0,ac1,ac2,error;
-
- ac0 = (char *) "=";
- ac1 = (char *) dirbuf;
- ac2 = MAXPATH+1;
-
- error = sys($GNAME,&ac0,&ac1,&ac2);
- if (error == NULL)
- *(dirbuf+ac2) = '\000'; /* null terminator */
-
- return(error);
- }
-
-